namespace ghost {
    /**羔羊缓动类*/
    export class GYTween {
        private _startTime: number;
        public delay: number;
        public updateFunc: Function;
        public completeFunc: Function;
        public startFunc: Function;
        public thisObject: any;
        public duration: number = 0;
        public target: IResource;
        public tweenArr: Array<TweenData>;
        // private _intervalId: number;
        private _isRunning: boolean;
        private _isReserve: boolean;
        private _completeClear: boolean;
        public keepFrom: boolean;

        public constructor() {
            var s = this;
            s._startTime = 0;
            s.delay = 0;
            s.updateFunc = null;
            s.completeFunc = null;
            s.startFunc = null;
            s.thisObject = null;
            s.duration = 0;
            s.target = null;
            s.tweenArr = null;
            // s._intervalId = -1;
            s._isRunning = false;
            s._isReserve = false;
            s._completeClear = false;
        }
        /**@param s.isReserve 是否翻转播放*/
        public run(isReserve: boolean = false): void {
            var s = this;
            s.stop();
            // if (s._intervalId > -1) {
            //     clearInterval(s._intervalId);
            //     s._intervalId = -1;
            // }
            Laya.timer.clear(s, s.toRun);
            if (s.delay > 0) {
                Laya.timer.once(s.delay, s, s.toRun, [isReserve]);
            }
            else
                s.toRun(isReserve);
        }
        public toRun(isReserve: boolean = false): void {
            var s = this;
            if (s.target.disposed || s.target["destroyed"])//兼容laya
            {
                s.clear();
                return;
            }            
            s._isReserve = isReserve;
            s._startTime = CommonUtil.loopTime;
            var len: number;                        
            len = s.tweenArr.length;
            while (--len > -1) {
                var data: TweenData = s.tweenArr[len];                
                if (data.ease == null) data.ease = GYTween.commonEase;                
                if (!s.keepFrom)
                    if (isNaN(data.initFrom)) data.initFrom = s.target[data.propertyName];
                if (s._isReserve) {
                    data.from = data.initTo;
                    data.to = (!s.keepFrom || data.initFrom == data.initFrom) ? data.initFrom : s.target[data.propertyName];
                }
                else {
                    data.from = (!s.keepFrom || data.initFrom == data.initFrom) ? data.initFrom : s.target[data.propertyName];
                    data.to = data.initTo;
                }
            }
            if (s.startFunc != null) s.startFunc.call(s.thisObject, s.target);
            if (!s._isRunning) {
                CommonUtil.addStageLoop(s.loop, s);
                s._isRunning = true;
                s.loop(s._startTime);

            }
        }
        public stop(): void {
            let s = this;
            // if (s._intervalId > -1) {
            //     clearInterval(s._intervalId);
            //     s._intervalId = -1;
            // }
            Laya.timer.clear(s, s.toRun);
            if (!s._isRunning) return;
            s._isRunning = false;
            CommonUtil.delStageLoop(s.loop, s);
        }
        public get isRunning(): boolean {
            var s = this;
            return s._isRunning;
        }
        private loop(t: number): void {
            var s = this;
            var len: number;
            var compFunc: Function, sObj: any, tar: any;
            if (s.target.disposed || s.target["destroyed"])//兼容laya
            {
                s.clear();
                return;
            }
            len = s.tweenArr.length;
            while (--len > -1)
                (s.tweenArr[len] as TweenData).ease(s.tweenArr[len], this);
            if (s.updateFunc != null) s.updateFunc.call(s.thisObject, s.target);
            if (CommonUtil.loopTime >= s._startTime + s.duration) {
                compFunc = s.completeFunc;
                sObj = s.thisObject;
                tar = s.target;
                if (s._completeClear)
                    s.clear();
                else {
                    s._isRunning = false;
                    CommonUtil.delStageLoop(s.loop, s);
                }
                if (compFunc != null) compFunc.call(sObj, tar);
            }
        }
        /**销毁GYTween对象
         * @param tar 操控的显示对象
         * */
        public static disposeByTarget(tar: any): void {
            let len: number;
            len = GYTween._useTween.length;
            while (--len > -1) {
                if (GYTween._useTween[len].target == tar) {
                    GYTween._useTween[len].clear(false);
                    GYTween._useTween.splice(len, 1);
                }
            }
        }
        public clear(removeUse: boolean = true): void {
            var s = this;
            if (s.target == null) return;            
            GYTween._pool.push(this);
            if (removeUse) {
                let ind: number = GYTween._useTween.indexOf(this);
                if (ind > -1) {
                    GYTween._useTween.splice(ind, 1);
                }
            }
            var len: number;
            len = s.tweenArr.length;
            while (--len > -1)
                (s.tweenArr[len] as TweenData).clear();
            s.tweenArr = null;
            s.target = null;
            s.duration = 0;
            s.delay = 0;
            s.completeFunc = null;
            s.startFunc = null;
            s.updateFunc = null;
            s.thisObject = null;
            s._isRunning = false;
            s._completeClear = false;
            s._isReserve = false;
            CommonUtil.delStageLoop(s.loop, s);
            // if (s._intervalId > -1) {
            //     clearInterval(s._intervalId)
            //     s._intervalId = -1;
            // }
            Laya.timer.clear(s, s.toRun);
        }
        public get startTime(): number {
            var s = this;
            return s._startTime;
        }

        /**播放完成后自动清理tween*/
        public get completeClear(): boolean {
            var s = this;
            return s._completeClear;
        }

        public set completeClear(value: boolean) {
            var s = this;
            s._completeClear = value;
        }

        /**是否翻转播放*/
        public get isReserve(): boolean {
            var s = this;
            return s._isReserve;
        }

        /**匀速缓动*/
        public static commonEase(tData: TweenData, t: GYTween): void {
            var per: number = t.duration == 0 ? 1 : ((CommonUtil.loopTime - t.startTime) / t.duration);
            if (per > 1) {
                per = 1;
                t.target[tData.propertyName] = tData.to;
                return;
            }
            t.target[tData.propertyName] = tData.from + (tData.to - tData.from) * per;
        }
        /**加速缓动*/
        public static addEase(tData: TweenData, t: GYTween): void {
            var per: number = t.duration == 0 ? 1 : ((CommonUtil.loopTime - t.startTime) / t.duration);
            var s: number = tData.to - tData.from;
            if (per > 1) {
                per = 1;
                t.target[tData.propertyName] = tData.to;
                return;
            }
            per = per * per;
            t.target[tData.propertyName] = tData.from + s * per;
        }
        /**减速缓动*/
        public static reduceEase(tData: TweenData, t: GYTween): void {
            var per: number = 1 - (t.duration == 0 ? 1 : ((CommonUtil.loopTime - t.startTime) / t.duration));
            var s: number = tData.to - tData.from;
            if (per < 0) {
                per = 0;
                t.target[tData.propertyName] = tData.to;
                return;
            }
            per = per * per;
            t.target[tData.propertyName] = tData.from + s * (1 - per);
        }
        private static _pool: GYTween[];
        private static _useTween: GYTween[] = [];
        public static to(target: any, tweenArr: Array<TweenData>, duration: number, delay: number = 0, thisObject: any = null, completeFunc: Function = null, startFunc: Function = null, updateFunc: Function = null, runImmediate: boolean = true, isClear: boolean = true): GYTween {
            if (!GYTween._pool) {
                GYTween._pool = new Array<GYTween>();
            }
            var t: GYTween = (GYTween._pool.length == 0 ? new GYTween() : GYTween._pool.pop());
            t.target = target;
            t.tweenArr = tweenArr;
            t.duration = duration;
            t.delay = delay;
            t.completeFunc = completeFunc;
            t.startFunc = startFunc;
            t.updateFunc = updateFunc;
            t.thisObject = thisObject;
            t.completeClear = isClear;
            GYTween._useTween.push(t);
            if (runImmediate)
                t.run();
            return isClear ? null : t;
        }

        /***对已经被销毁的对象的tween进行垃圾回收*/
        public static gc(): void {
            let len: number;
            let tween: GYTween;
            len = GYTween._useTween.length;
            while (--len > -1) {
                tween = GYTween._useTween[len];
                if (tween.target.disposed) {
                    tween.clear(false);
                    GYTween._useTween.splice(len, 1);
                }
            }
        }
    }
}
